package goActorsInstance

import (
	"goActorsCommon"
	"goActorsNaming"
	"os"
	"net"
	"rpc"
)

type GoInstance struct {
	Actors_Pid	map[int32] * GoActor
	Actors_Name	map[string] int32
	PidCounter	int32
	Pid			* goActorsCommon.GoInstancePid
	NamingPid	* goActorsNaming.GoActorsNamingPid
}

func New_GoInstance( ip string, namingPid *goActorsNaming.GoActorsNamingPid ) ( gi * GoInstance, error os.Error ) {
	gi = &GoInstance {
		Actors_Pid	: map[int32] * GoActor { },
		Actors_Name	: map[string] int32 { },
		PidCounter	: 0,
		Pid			: goActorsCommon.New_GoInstancePid( ip, 0 ),
		NamingPid	: namingPid,
	}
	
//	gia := New_GoInstanceNaming( gi )
	
	// Starts RPC Service
	server := rpc.NewServer()
	server.Register ( gi )
	l, e := net.ListenTCP ( "tcp", &net.TCPAddr{ make([]byte, 0, 0), 0 } )
	if ( e != nil ) {
		return nil, e
	}
	go server.Accept( l )
	addr, _ := l.Addr().(* net.TCPAddr)
	gi.Pid.Port = addr.Port
	
	goActorsCommon.RegisterTypesGob()
	
	return gi, nil
}

func ( gi *GoInstance ) Receive( message *goActorsCommon.MessageWrapper, result * bool ) os.Error {
	actor, exists := gi.Actors_Pid[message.GoActor]
	if !exists {
		(*result) = false
		return os.NewError( "Invalid GoActor." )
	}
	select { 
		case actor.MessageBox <- message.Message:
			return nil 
		default:
			return os.NewError( "Can't deliver message." )
	} 
	return nil
}

/*func (gi * GoInstance) ResolveLocal ( name string ) bool {
	_, exists := gi.Actors_Name[name]
	return exists
}*/

func (gi * GoInstance) resolve ( name string ) ( pid *goActorsCommon.GoActorPid, error os.Error ) {
	localPid, exists := gi.Actors_Name[name]
	if ( exists ) {
		return gi.Actors_Pid[localPid].Pid, nil
	}
	
	pid1, error := gi.NamingPid.Resolve( name )
	if error != nil {
		return nil, error
	}
	
	pid, ok := pid1.( *goActorsCommon.GoActorPid )
	if !ok {
		return nil, os.NewError( "Name not found." )
	}
	
	return pid, nil
}

func (gi * GoInstance) register ( name string, pid *goActorsCommon.GoActorPid ) os.Error {
	_, exists := gi.Actors_Name[name]
	if ( exists ) {
		return os.NewError( "Name allready in use." )
	}
	
	_, error := gi.NamingPid.Register( name, pid )
	if error != nil {
		return error
	}
	
	gi.Actors_Name[name] = pid.GoActor
	return nil
}

func (gi * GoInstance) unRegister ( name string ) os.Error {
	_, exists := gi.Actors_Name[name]
	if ( !exists ) {
		return os.NewError( "Name not registered." )
	}
	
	gi.Actors_Name[name] = 0, false
	return nil
}

func (gi * GoInstance) new_GoActor ( object Runnable ) * goActorsCommon.GoActorPid {
	pid := goActorsCommon.New_GoActorPid( gi.Pid, gi.PidCounter )
	ga := &GoActor{
		MessageBox	: make(chan * goActorsCommon.Message),
		object		: object,
		instance	: gi,
		Pid			: pid,
	}
	gi.Actors_Pid[gi.PidCounter] = ga
	gi.PidCounter++
	object.SetActor( ga )
	go object.Run()
	return ga.Pid
}

